﻿using STHPMS1.BLL.B_Core;
using STHPMS1.Common.C_Entity.Stmpms1;
using STHPMS1.ICore.I_BLL.Bus;
using STHPMS1.ICore.I_Entity.Info;
using STHPMS1.ICore.I_Entity.Stmpms1;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Linq;
using STHPMS1.ICore.I_DAL;
using System.Data;
using System.Collections;
using System.Dynamic;

namespace STHPMS1.BLL.B_Bus
{
    public class Dr_LifecyclecostBus : BllBase, IDr_LifecyclecostBill
    {
        public void Save<T>(T entity)
            where T : class ,IDr_Lifecyclecost
        {
            if (this.Scene.Dal.Sthpms1.Update(entity) == 0)
            {
                this.Scene.Dal.Sthpms1.Insert(entity);
            }
        }

        public void Remove(IDr_Lifecyclecost entity)
        {
            this.Scene.Dal.Sthpms1.Delete(entity);
        }

        public IEnumerable<T> Get<T>(Expression<Func<T, bool>> predicate, IPagingInfo info)
            where T : class, IDr_Lifecyclecost
        {
            return this.Scene.Dal.Sthpms1.Select<T>(predicate, info);
        }

        public dynamic GetCycleLifeCost(string proj_Id)
        {
            dynamic data = new ArrayList();
            foreach (var cost in this.Get<Dr_Lifecyclecost>(p => p.Proj_Id == proj_Id, null))
            {
                Dr_Largemeas_Ini iniPlan = this.Scene.Dal.Sthpms1.Select<Dr_Largemeas_Ini>(p => p.Iniproj_Id == cost.Iniproj_Id).FirstOrDefault();
                if (iniPlan == null) throw new Exception("大中修初选方案不存在 - "+cost.Iniproj_Id);
                dynamic json = new ExpandoObject();
                json.id = iniPlan.Iniproj_Id;
                json.name = iniPlan.Meas_Name;
                json.data = new double[3]{
                    (double)cost.Inicons_Cost/10000,
                    (double)cost.Schecost/10000,
                    (double)cost.Lifecost/10000
                };

                data.Add(json);
            }
            return data;
        }

        public void CalacFullLifeCycleCost(string proj_Id)
        {
            ISthpms1Dao dao=this.Scene.Dal.Sthpms1;
            Dr_Decision_Tree decision = dao.Select<Dr_Decision_Tree>(p => p.Proj_Id == proj_Id).FirstOrDefault();
            if (decision == null) throw new Exception("比选方案不存在 - " + proj_Id);
            if (!string.IsNullOrEmpty(decision.Recom_Meaid)) throw new Exception("比选方案已生成推荐初选方案!");
            Dn_Divi_Result mainSeg = dao.Select<Dn_Divi_Result>(p => p.Mainsegid == decision.Mainsegid).FirstOrDefault();
            if (mainSeg==null) throw new Exception("路段信息不存在 - "+decision.Mainsegid);

            List<Dr_Initialconstruction> initalCost = dao.Select<Dr_Initialconstruction>(p => p.Proj_Id == proj_Id);
            if (initalCost.Count == 0) throw new Exception("路面初期建设费用还没有计算!");
            List<Dr_Repaircost> repairCost = dao.Select<Dr_Repaircost>(p => p.Proj_Id == proj_Id);
            if (repairCost.Count == 0) throw new Exception("请先制定养护计划!");
            List<Df_Dailymian_Cost> dailyCost = dao.Select<Df_Dailymian_Cost>();
            if (dailyCost.Count == 0) throw new Exception("路面日常养护单价数据为空");
            //List<Dr_Maintainprice> mainCost = dao.Select<Dr_Maintainprice>();
            //if (mainCost.Count == 0) throw new Exception("养护类型默认养护单价数据为空");

            Dictionary<string, double> initCostList = new Dictionary<string, double>();//比选方案的初期建设费用
            foreach (Dr_Initialconstruction item in initalCost)
            {
                if(initCostList.ContainsKey(item.Iniproj_Id))
                {
                    initCostList[item.Iniproj_Id] += (double)item.Inicons_Cost;
                }
                else
                {
                    initCostList.Add(item.Iniproj_Id,(double) item.Inicons_Cost);
                }
            }

            Df_Dailymian_Cost dailyC=dailyCost.Where(p=>p.Pvmttype==mainSeg.Pvmttype && p.Rd_Class.Contains(mainSeg.Rdclass_Dictid.ToString())).FirstOrDefault();
            if(dailyC==null)throw new Exception("日常养护单价数据为空 - "+mainSeg.Pvmttype+":"+mainSeg.Rdclass_Dictid.ToString());
            double dailyUnitCost = (double)(dailyC.Daily_Unitcost * (mainSeg.Endmp - mainSeg.Beginmp) / 1000);//日常养护费用单价

            double minNav=double.MaxValue;
            List<Dr_Lifecyclecost> lifeCostList = new List<Dr_Lifecyclecost>();//全寿命周期费用
            foreach (var item in initCostList)
            {
                Dr_Lifecyclecost lifeCost = new Dr_Lifecyclecost();
                lifeCost.Proj_Id = proj_Id;
                lifeCost.Iniproj_Id = item.Key;
                lifeCost.Inicons_Cost = item.Value;
                lifeCost.Mainsegid = decision.Mainsegid;

                var repairList= repairCost.Where(p => p.Iniproj_Id == item.Key).OrderBy(p => p.Main_Year);
                var index=0;

                if (repairList.Count() == 0)
                    lifeCost.Schecost = 0;
                else
                    lifeCost.Schecost = repairList.ElementAt(0).Schecost;

                lifeCost.Lifecost = lifeCost.Inicons_Cost + lifeCost.Schecost;

                double npv=0;
                double nav=0;
                Dr_Repaircost r = repairList.ElementAt(index++);
                for (int i = 1; i <= decision.Analy_Period; i++)
			    {                    
                    double c_npv=dailyUnitCost;//当年费用
                    if (r.Main_Year == i)
                    {
                        c_npv = (double)r.Annu_Maincost;
                        if (index < repairList.Count() - 1)
                            r = repairList.ElementAt(index++);
                    }

                    c_npv= c_npv / Math.Pow(1 + (double)decision.Discou_Rate, i);
                    npv += c_npv;
                    nav += c_npv * ((i * Math.Pow(1 + i, (double)decision.Analy_Period)) / (Math.Pow(1 + i, (double)decision.Analy_Period)-1));
			    }

                lifeCost.Npv=npv + item.Value;//各年维护费用+初期建设费用
                lifeCost.Nav=nav;
                lifeCostList.Add(lifeCost);

                if(nav<minNav)
                {
                    decision.Recom_Meaid = item.Key;
                    minNav = nav;
                }
            }

            using (IDbTransaction tran = dao.BeginTransaction())
            {
                dao.Delete<Dr_Lifecyclecost>(p => p.Proj_Id == proj_Id);
                dao.Save<Dr_Decision_Tree>(decision);
                dao.InsertAll<Dr_Lifecyclecost>(lifeCostList);
                tran.Commit();
            }            
        }
    }
}
